home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
gfx
/
show
/
swfplayersrc.lha
/
Lib
/
sound.cc
< prev
next >
Wrap
C/C++ Source or Header
|
2002-11-05
|
16KB
|
757 lines
/////////////////////////////////////////////////////////////
// Flash Plugin and Player
// Copyright (C) 1998,1999 Olivier Debon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
///////////////////////////////////////////////////////////////
// Author : Olivier Debon <odebon@club-internet.fr>
//
#include "swf.h"
#ifndef NOSOUND
#ifndef AMIGA
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/soundcard.h>
#else
/* Amiga includes */
extern "C" {
#include <clib/alib_protos.h>
#ifdef __PPC__
#define DOS_DOSEXTENS_H
#include </ADE/os-includeppc/proto/dos.h>
#undef DOS_DOSEXTENS_H
#include </ADE/os-includeppc/proto/exec.h>
#else
#include <clib/exec_protos.h>
#endif
#include <devices/audio.h>
#include <exec/memory.h>
#include <graphics/gfxbase.h>
}
struct channel_info {
struct MsgPort *audio_mp;
struct IOAudio *audio_io;
BOOL sound_in_progress;
};
static struct channel_info channel_info[2] =
{
{FALSE, NULL, NULL},
{FALSE, NULL, NULL},
};
static struct MsgPort *audio_mp = NULL;
static struct IOAudio *audio_io = NULL;
static BOOL audio_is_open = FALSE;
extern struct GfxBase *GfxBase;
static ULONG clock_constant;
static ULONG amiga_period;
static UBYTE sound_in_progress = 0;
#endif // !AMIGA
#endif // !NOSOUND
#ifdef RCSID
static char *rcsid = "$Id: sound.cc,v 1.11 1999/01/31 21:14:22 olivier Exp $";
#endif
#define PRINT 0
//////////// SOUND
Sound::Sound(long id) : Character(SoundType, id)
{
samples = 0;
stereo = 0;
soundRate = 0;
sampleSize = 1;
}
Sound::~Sound()
{
if (samples) {
delete samples;
}
}
void
Sound::setSoundFlags(long f) {
switch (GET_SOUND_RATE_CODE(f)) {
case 0:
soundRate = 5500;
break;
case 1:
soundRate = 11000;
break;
case 2:
soundRate = 22000;
break;
case 3:
soundRate = 44000;
break;
}
if (f & soundIs16bit) {
sampleSize = 2;
}
if (f & soundIsStereo) {
stereo = 1;
}
#if PRINT
printf("-----\nFlags = %2x\n", f);
printf("Rate = %d kHz ", soundRate);
printf("SampleSize = %d byte(s) ", sampleSize);
if (f & soundIsStereo) {
printf("Stereo ");
} else {
printf("Mono ");
}
if (f & soundIsADPCMCompressed) {
printf("ADPCM\n");
} else {
printf("Raw\n");
}
#endif
}
char *
Sound::setNbSamples(long n) {
long size;
nbSamples = n;
size = nbSamples * (stereo ? 2 : 1) * sampleSize;
samples = new char[ size ];
memset((char *)samples,0, size);
return samples;
}
long
Sound::getRate() {
return soundRate;
}
long
Sound::getChannel() {
return stereo ? 2 : 1;
}
long
Sound::getNbSamples() {
return nbSamples;
}
long
Sound::getSampleSize() {
return sampleSize;
}
char *
Sound::getSamples() {
return samples;
}
//////////// SOUND MIXER
long SoundMixer::dsp = -1; // Init of descriptor
long SoundMixer::blockSize = 0; // Driver sound buffer size
long SoundMixer::nbInst = 0; // Nb SoundMixer instances
long SoundMixer::sampleSize = 0;
long SoundMixer::stereo = 0;
long SoundMixer::soundRate = 0;
char *SoundMixer::buffer = 0;
SoundMixer::SoundMixer(char *device)
{
#ifndef NOSOUND
#ifdef AMIGA
dsp = -1;
audio_is_open = FALSE;
perror("Linux specific");
#else
int status;
long fmt;
list = 0; // No sound to play
if (nbInst++) {
// Device is already open
return;
}
dsp = open(device,O_WRONLY);
if (dsp < 0) {
perror("open dsp");
return;
}
// Reset device
status = ioctl(dsp, SNDCTL_DSP_RESET);
if (status < 0) perror("ioctl SNDCTL_DSP_RESET");
// Set sample size
fmt = AFMT_S16_LE;
sampleSize = 2;
status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
if (status) {
fmt = AFMT_U8;
sampleSize = 1;
status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
}
// Set stereo channel
stereo = 1;
status = ioctl(dsp, SNDCTL_DSP_STEREO, &stereo);
if (status) {
stereo = 0;
}
// Set sound rate in Hertz
soundRate = 11000;
status = ioctl(dsp, SNDCTL_DSP_SPEED, &soundRate);
if (status < 0) perror("ioctl SNDCTL_DSP_SPEED");
// Get device buffer size
status = ioctl(dsp, SNDCTL_DSP_GETBLKSIZE, &blockSize);
if (status < 0) perror("ioctl SNDCTL_DSP_GETBLKSIZE");
if (blockSize < 1024) {
blockSize = 32768;
}
blockSize *= 2;
buffer = (char *)malloc(blockSize);
if (buffer == 0) {
close(dsp);
dsp = -1;
}
#if PRINT
int caps;
ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
printf("Audio capabilities = %x\n", caps);
printf("Sound Rate = %d\n", soundRate);
printf("Stereo = %d\n", stereo);
printf("Sample Size = %d\n", sampleSize);
printf("Buffer Size = %d\n", blockSize);
#endif /* PRINT */
#endif /* NOSOUND */
#endif /* AMIGA */
}
SoundMixer::SoundMixer(int flags)
{
#ifndef NOSOUND
#ifndef AMIGA
dsp = -1;
perror("Amiga specific");
#else
int status;
long fmt;
int i;
UBYTE MyChannels [] = {1,2,4,8};
UBYTE chans[1];
struct channel_info *c;
buffer1 = (char *) NULL;
buffer2 = (char *) NULL;
list = 0; // No sound to play
if (nbInst++) {
// Device is already open
return;
}
if ((audio_mp = CreatePort (NULL, 0)) == NULL ||
(audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
{
fprintf(stderr,"SoundInit error 1\n");
return;
}
chans[0] = 3;
audio_io->ioa_Request.io_Message.mn_ReplyPort = audio_mp;
audio_io->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
audio_io->ioa_AllocKey = 0;
audio_io->ioa_Data = chans;
audio_io->ioa_Length = sizeof(chans);
if (OpenDevice((const char *) AUDIONAME, 0, (struct IORequest *)audio_io, 0) != 0) // [SHA, 03/10/2002 : PPC compilation]
{
#if PRINT
fprintf(stderr,"OpenDevice(\"audio.device\") failed. Sound disabled.\n");
#endif
return;
}
audio_is_open = TRUE;
for (i = 0; i < 2; i++)
{
c = &channel_info[i];
if ((c->audio_mp = CreatePort (NULL, 0)) == NULL ||
(c->audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
{
fprintf(stderr,"SoundInit error 2\n");
return;
}
*c->audio_io = *audio_io;
c->audio_io->ioa_Request.io_Message.mn_ReplyPort = c->audio_mp;
c->audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << i);
}
if ((GfxBase->DisplayFlags & NTSC) != 0)
clock_constant = 3579545; /* NTSC */
else
clock_constant = 3546895; /* PAL */
dsp = 1; /* pretend we've opened the Linux sound device... */
// Set stereo channel
if (flags & AMIGAFLAG_MONO)
stereo = 0; // mono sound
else
stereo = 1; // stereo
// Set sound rate in Hertz
soundRate = 11000;
amiga_period = ((clock_constant << 1) + soundRate) / (((unsigned long) soundRate) << 1);
blockSize = 64 * 1024; /* 64K ??????????????? */
if (stereo)
{
/* RESULT NOT CHECKED!! */
buffer1 = (char *) AllocVec(blockSize, MEMF_CHIP);
buffer2 = (char *) AllocVec(blockSize, MEMF_CHIP);
buffer = buffer1;
}
else
{
buffer = (char *) AllocVec(blockSize, MEMF_CHIP);
}
#if PRINT
int caps;
ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
printf("Audio capabilities = %x\n", caps);
printf("Sound Rate = %d\n", soundRate);
printf("Stereo = %d\n", stereo);
printf("Sample Size = %d\n", sampleSize);
printf("Buffer Size = %d\n", blockSize);
#endif /* PRINT */
#endif /* NOSOUND */
#endif /* AMIGA */
}
#ifdef AMIGA
void static AmigaStopSound(int handle)
{
struct channel_info *c;
if (channel_info[handle].sound_in_progress)
{
/* Set the volume to 0 before aborting the audio, else we'll get a 'click' */
// audio_io->ioa_Request.io_Command = ADCMD_PERVOL;
// audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
// audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << handle);
// audio_io->ioa_Period = amiga_period;
// audio_io->ioa_Volume = 0;
// BeginIO ((struct IORequest *)audio_io);
// WaitPort (audio_mp);
// GetMsg (audio_mp);
/*
if (!CheckIO((struct IORequest *)channel_info[handle].audio_io))
{
printf("already playing. Waiting\n");
WaitPort (channel_info[handle].audio_mp); // clears signal & returns immediately
GetMsg (channel_info[handle].audio_mp);
printf("finished\n");
channel_info[handle].sound_in_progress = FALSE;
return;
}
printf("Aborting\n");
*/
AbortIO ((struct IORequest *)channel_info[handle].audio_io);
WaitPort (channel_info[handle].audio_mp);
GetMsg (channel_info[handle].audio_mp);
channel_info[handle].sound_in_progress = FALSE;
}
}
#endif
SoundMixer::~SoundMixer()
{
#ifndef AMIGA
if (--nbInst == 0) {
if (dsp > 0) {
close(dsp);
free(buffer);
}
}
#else
int i;
if (--nbInst == 0)
{
if (audio_is_open)
{
for (i = 0; i < 2; i++) AmigaStopSound (i);
audio_io->ioa_Request.io_Unit = (struct Unit *) ((1 << 2) - 1); /* free numChannels channels */
CloseDevice ((struct IORequest *)audio_io);
audio_is_open = FALSE;
}
for (i = 0; i < 2; i++)
{
if (channel_info[i].audio_io != NULL)
{
FreeMem (channel_info[i].audio_io, sizeof(struct IOAudio));
channel_info[i].audio_io = NULL;
}
if (channel_info[i].audio_mp != NULL)
{
DeletePort (channel_info[i].audio_mp);
channel_info[i].audio_mp = NULL;
}
}
if (audio_io != NULL)
{
FreeMem (audio_io, sizeof(struct IOAudio));
audio_io = NULL;
}
if (audio_mp != NULL)
{
DeletePort (audio_mp);
audio_mp = NULL;
}
if (buffer1)
{
FreeVec(buffer1);
buffer1 = (char *) NULL;
}
if (buffer2)
{
FreeVec(buffer2);
buffer2 = (char *) NULL;
}
}
#endif
}
void
SoundMixer::stopSounds()
{
#ifndef NOSOUND
SoundList *sl,*del;
for(sl = list; sl; ) {
del = sl;
sl = sl->next;
delete del;
}
list = 0;
#endif
}
void
SoundMixer::startSound(Sound *sound)
{
#ifndef NOSOUND
SoundList *sl;
if (sound) {
// Add sound in list
sl = new SoundList;
sl->rate = sound->getRate();
sl->stereo = (sound->getChannel() == 2);
sl->sampleSize = sound->getSampleSize();
sl->current = sound->getSamples();
sl->remaining = sound->getSampleSize()*sound->getNbSamples()*sound->getChannel();
sl->next = list;
list = sl;
}
#endif
}
long
SoundMixer::playSounds()
{
#ifndef NOSOUND
#ifndef AMIGA
audio_buf_info bufInfo;
#endif
long nbBytes, n;
SoundList *sl,*prev;
int status;
// Init failed
if (dsp < 0) return 0;
// No sound to play
if (list == 0) return 0;
#ifndef AMIGA
// Get free DMA buffer space
status = ioctl(dsp, SNDCTL_DSP_GETOSPACE, &bufInfo);
// Free space is not large enough to output data without blocking
// But there are still sounds to play. We must wait.
if (bufInfo.bytes < blockSize) return 1;
#endif
nbBytes = 0;
// Fill buffer with silence.
memset((void*)buffer, 0, blockSize);
prev = 0;
sl = list;
while(sl) {
// Ask sound to fill the buffer
// according to device capabilities
n = fillSoundBuffer(sl, buffer, blockSize);
// Remember the largest written size
if (n > nbBytes) {
nbBytes = n;
}
// No more samples for this sound
if (sl->remaining == 0) {
// Remove sound from list
if (prev) {
prev->next = sl->next;
delete sl;
sl = prev->next;
} else {
list = sl->next;
delete sl;
sl = list;
}
} else {
sl = sl->next;
}
}
if (nbBytes) {
#ifndef AMIGA
// At last ! Play It !
write(dsp,buffer,nbBytes);
status = ioctl(dsp, SNDCTL_DSP_POST);
#else
struct channel_info *c;
int ss;
UBYTE *lbuffer,*rbuffer;
if (stereo)
{
ss = nbBytes >> 1; /* buffer contains both the left & right channels, so the length is halved */
lbuffer = (UBYTE *) buffer;
rbuffer = (UBYTE *) buffer + (blockSize >> 1);
}
else
{
/* mono */
ss = nbBytes;
lbuffer = (UBYTE *) buffer;
rbuffer = (UBYTE *) buffer;
}
#if PRINT
printf("playing ladr=%p radr=%p len=%d (%d) stereo=%d\n",lbuffer,rbuffer,nbBytes, ss,stereo);
#endif
/* Wait for the sample to stop playing??? */
AmigaStopSound(0);
c = &channel_info[0];
c->audio_io->ioa_Request.io_Command = CMD_WRITE;
c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
c->audio_io->ioa_Data = lbuffer;
c->audio_io->ioa_Length = ss;
c->audio_io->ioa_Period = amiga_period;
c->audio_io->ioa_Volume = 63;
c->audio_io->ioa_Cycles = 1;
//BeginIO ((struct IORequest *)c->audio_io);
SendIO ((struct IORequest *)c->audio_io);
c->sound_in_progress = TRUE;
AmigaStopSound(1);
c = &channel_info[1];
c->audio_io->ioa_Request.io_Command = CMD_WRITE;
c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
c->audio_io->ioa_Data = rbuffer;
c->audio_io->ioa_Length = ss;
c->audio_io->ioa_Period = amiga_period;
c->audio_io->ioa_Volume = 63;
c->audio_io->ioa_Cycles = 1;
// BeginIO ((struct IORequest *)c->audio_io);
SendIO ((struct IORequest *)c->audio_io);
c->sound_in_progress = TRUE;
if (stereo)
{
/* switch 'buffer' to point to the correct sound buffer */
if (buffer == buffer1)
buffer = buffer2;
else
buffer = buffer1;
}
#endif
}
return nbBytes;
#else
return 0;
#endif
}
long
SoundMixer::fillSoundBuffer(SoundList *sl, char *buff, long buffSize)
{
long sampleLeft, sampleRight;
long skipOut, skipOutInit;
long skipIn, skipInInit;
long freqRatio;
long totalOut = 0;
sampleLeft = sampleRight = 0;
skipOutInit = skipInInit = 0;
freqRatio = sl->rate / soundRate;
if (freqRatio) {
skipOutInit = freqRatio - 1;
skipInInit = 0;
}
freqRatio = soundRate / sl->rate;
if (freqRatio) {
skipInInit = freqRatio - 1;
skipOutInit = 0;
}
skipOut = skipOutInit;
skipIn = skipInInit;
while (buffSize && sl->remaining) {
if (skipIn-- == 0) {
// Get sampleLeft
if (sl->sampleSize == 2) {
sampleLeft = (long)(*(short *)(sl->current));
if (sampleSize == 1) {
sampleLeft = (sampleLeft >> 8) &0xff;
}
} else {
sampleLeft = (long)*(sl->current);
if (sampleSize == 2) {
sampleLeft <<= 8;
}
}
sl->current += sl->sampleSize;
sl->remaining -= sl->sampleSize;
if (sl->stereo) {
// Get sampleRight
if (sl->sampleSize == 2) {
sampleRight = (long)(*(short *)(sl->current));
if (sampleSize == 1) {
sampleRight = (sampleRight >> 8) &0xff;
}
} else {
sampleRight = (long)*(sl->current);
if (sampleSize == 2) {
sampleRight <<= 8;
}
}
sl->current += sl->sampleSize;
sl->remaining -= sl->sampleSize;
} else {
sampleRight = sampleLeft;
}
skipIn = skipInInit;
}
if (skipOut-- == 0) {
// Output
if (stereo) {
if (sampleSize == 2) {
*((short *)buff) += sampleLeft/2;
buffSize -= sampleSize;
buff += sampleSize;
*((short *)buff) += sampleRight/2;
buffSize -= sampleSize;
buff += sampleSize;
} else {
*((char *)buff) += sampleLeft/2;
buffSize -= sampleSize;
buff += sampleSize;
*((char *)buff) += sampleRight/2;
buffSize -= sampleSize;
buff += sampleSize;
}
totalOut += 2*sampleSize;
} else {
if (sampleSize == 2) {
*((short *)buff) += (sampleLeft+sampleRight)>>2;
buffSize -= sampleSize;
buff += sampleSize;
} else {
*((char *)buff) += (sampleLeft+sampleRight)>>2;
buffSize -= sampleSize;
buff += sampleSize;
}
totalOut += sampleSize;
}
skipOut = skipOutInit;
}
}
return totalOut;
}